#    Copyright 2008, 2009 Tri-County Electric Cooperative, St. Matthews, South Carolina
#    This file is part of COOPGIS.
#    COOPGIS is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#    COOPGIS is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#    You should have received a copy of the GNU General Public License
#    along with COOPGIS.  If not, see <http://www.gnu.org/licenses/>.
#************************BEGIN Add Include Files to Path************************
import sys
NeededPaths=['/opt/coopgis/djangoproject/include', '/opt/coopgis/djangoproject']
for path in NeededPaths:
    if(not path in sys.path):
        sys.path.append(path)
#************************END   Add Include Files to Path************************
import application, cis, command, geography, oms, staker, symbology, unsorted
import COOPGIS_Ajax, COOPGIS_GPS, COOPGIS_Misc, COOPGIS_ReportLab, COOPGIS_String, COOPGIS_Update
import os, csv, shutil, datetime, time, reportlab, djangoproject.settings
from django.contrib.gis.db import models
from django.contrib.gis.geos import *
from django.http import HttpResponse
from django.contrib import admin
from django.db.models import Max
import _mysql as mysql

def GetNumberOfPhases(assembly):
    NumberOfPhases=0
    if(assembly.PhaseAIndicator):
        NumberOfPhases=NumberOfPhases+1
    if(assembly.PhaseBIndicator):
        NumberOfPhases=NumberOfPhases+1
    if(assembly.PhaseCIndicator):
        NumberOfPhases=NumberOfPhases+1
    if(assembly.PhaseNeutralIndicator):
        NumberOfPhases=NumberOfPhases+1
    return NumberOfPhases


class PoleTreatmentType(models.Model):
    """PoleTreatmentType is a list of Pole Treatment Types that have or could treat a pole"""
    Name=models.CharField(max_length=250)
    Description=models.TextField()
    objects=models.GeoManager()
    def __unicode__(self):
        return self.Name
    class Meta:
        db_table=u'coopgispoletreatmenttype'
        app_label='djangoproject'
    def GetOrCreate(self, Name, Description=''):
        try:
            New=PoleTreatmentType.objects.get(Name=Name)
            return New
        except:
            pass
        New=PoleTreatmentType()
        New.Name=Name
        New.Description=Description
        New.save()
        return New

class PoleTreatment(models.Model):
    """PoleTreatment is a list of treatments that have been applied to a given pole"""
    Pole=models.ForeignKey('Assembly')
    Company=models.ForeignKey('Company')
    PoleTreatmentType=models.ForeignKey('PoleTreatmentType', on_delete=models.PROTECT)
    PoleTreatmentDate=models.DateField()
    Description=models.TextField()
    CreateCommand=models.ForeignKey('Command', blank=True, null=True, on_delete=models.SET_NULL)
    #Pole Treatment Status Indicators
    BrokenCrossarmIndicator=models.NullBooleanField(blank=True, null=True)
    BrokenGuyIndicator=models.NullBooleanField(blank=True, null=True)
    BrokenInsulatorIndicator=models.NullBooleanField(blank=True, null=True)
    VisualInspectionIndicator=models.NullBooleanField(blank=True, null=True)
    VisualInspectionAndExcavationIndicator=models.NullBooleanField(blank=True, null=True)
    InternalTreatmentIndicator=models.NullBooleanField(blank=True, null=True)
    InternalVoidTreatmentIndicator=models.NullBooleanField(blank=True, null=True)
    LightningArrestorBlownIndicator=models.NullBooleanField(blank=True, null=True)
    NewPoleIndicator=models.NullBooleanField(blank=True, null=True)
    PoleLeaningIndicator=models.NullBooleanField(blank=True, null=True)
    SplitTopIndicator=models.NullBooleanField(blank=True, null=True)
    InternalDecayTreatmentIndicator=models.NullBooleanField(blank=True, null=True)
    WoodpeckerHolesIndicator=models.NullBooleanField(blank=True, null=True)
    WireNeutralLowIndicator=models.NullBooleanField(blank=True, null=True)
    WirePrimaryLowIndicator=models.NullBooleanField(blank=True, null=True)
    WireSecondaryLowIndicator=models.NullBooleanField(blank=True, null=True)
    RotIndicator=models.NullBooleanField(db_column='rotindicator', null=True, blank=True)
    #Pole Treatment Actions
    DataRecordOnlyIndicator=models.NullBooleanField(blank=True, null=True)
    GroundlineTreatmentIndicator=models.NullBooleanField(blank=True, null=True)
    RejectedIndicator=models.NullBooleanField(blank=True, null=True)
    RepairedGroundIndicator=models.NullBooleanField(blank=True, null=True)
    GuyMarkerReplacedQuantity=models.IntegerField(blank=True, null=True)
    GuyMarkerTotalQuantity=models.IntegerField(blank=True, null=True)
    GuyMarkerAdjustedIndicator=models.NullBooleanField(blank=True, null=True)
    CreateDateTime=models.DateTimeField(null=True, blank=True)
    LastModifyDateTime=models.DateTimeField(null=True, blank=True)
    CreateUserName=models.TextField(null=True, blank=True)
    LastModifyUserName=models.TextField(null=True, blank=True)
    ResidesOnServerIndicator=models.NullBooleanField(blank=True, null=True)
    #END NEED TO ADD TO DATABASE#
    objects=models.GeoManager()
    def __unicode__(self):
        return str(self.PoleTreatmentDate) + " " + str(self.PoleTreatmentType)
    class Meta:
        db_table=u'coopgispoletreatment'
        app_label='djangoproject'
    def GetOrCreate(self, Pole, PoleTreatmentDate, PoleTreatmentType, Company=None, Description='', CreateCommand=CreateCommand):
        New=PoleTreatment()
        New.Pole=Pole
        New.PoleTreatmentType=PoleTreatmentType
        New.Company=Company
        New.PoleTreatmentDate=PoleTreatmentDate
        New.Description=Description
        New.CreateCommand=CreateCommand
        New.GuyMarkerAdjustedIndicator=True
        New.save()
        return New

class PoleJointUseType(models.Model):
    """PoleJointUseType is a list of valid Joint Use Types, such as Fiber, Copper, etc"""
    Name=models.CharField(max_length=250)
    Description=models.TextField()
    objects=models.GeoManager()
    def __unicode__(self):
        return self.Name
    class Meta:
        db_table=u'coopgispolejointusetype'
        app_label='djangoproject'
    def GetOrCreate(self, Name, Description=''):
        try:
            New=PoleJointUseType.objects.get(Name=Name)
            return New
        except:
            pass
        New=PoleJointUseType()
        New.Name=Name
        New.Description=Description
        New.save()
        return New
        
class PoleJointUse(models.Model):
    """Pole Joint Use is a list of all attachments that other companies have to our poles"""
    Station=models.ForeignKey('Station')
    PoleJointUseType=models.ForeignKey('PoleJointUseType', on_delete=models.PROTECT)
    Company=models.ForeignKey('Company', on_delete=models.PROTECT)
    Quantity=models.IntegerField()
    ResidesOnServerIndicator=models.NullBooleanField(null=True, blank=True)
    CreateCommand=models.ForeignKey('Command', null=True, blank=True)
    objects=models.GeoManager()
    def __unicode__(self):
        return str(self.Quantity) + " " + str(self.Company) + " " + str(self.PoleJointUseType)
    class Meta:
        db_table=u'coopgispolejointuse'
        app_label='djangoproject'
    

        

class Company(models.Model):
    """Company is a list of companies that have or could treat a pole, manufacture a pole, or have a joint used"""
    Name=models.CharField(max_length=250)
    Description=models.TextField()
    PoleTreatmentIndicator=models.BooleanField()
    PoleJointUseIndicator=models.BooleanField()
    ManufacturerIndicator=models.BooleanField()
    VegetationManagementIndicator=models.BooleanField()
    ContractorIndicator=models.BooleanField()
    GroundRodTestIndicator=models.BooleanField(db_column='groundrodtestindicator')
    ResidesOnServerIndicator=models.BooleanField()
    CreateCommand=models.ForeignKey('Command', null=True, blank=True, on_delete=models.SET_NULL)
    objects=models.GeoManager()
    def __unicode__(self):
        return self.Name
    class Meta:
        db_table=u'coopgiscompany'
        app_label='djangoproject'
    def GetIndexWhenReverseSorted(self):
        Objects=Company.objects.all().order_by('-id')
        i = 0
        while(True):
            if(Objects[i] == self):
                return i
            i = i + 1
    def GetCommandidData(self):
        if(self.ResidesOnServerIndicator):
            return self.id, None
        return None, self.GetIndexWhenReverseSorted()



        
class AssemblyOwner(models.Model):
    """AssemblyOwner is a list of companies that could own an assembly, typical a member owns a pole."""
    Name=models.CharField(max_length=250)
    Description=models.TextField()
    objects=models.GeoManager()
    def __unicode__(self):
        return self.Name
    class Meta:
        db_table=u'coopgisassemblyowner'
        app_label='djangoproject'
    def GetOrCreate(self, Name, Description=''):
        try:
            New=AssemblyOwner.objects.get(Name=Name)
            return New
        except:
            pass
        New=AssemblyOwner()
        New.Name=Name
        New.Description=Description
        New.save()
        return New

class Material(models.Model):
    """Material holds a list of Materials a pole can be made out of"""
    Name=models.CharField(max_length=250)
    Description=models.TextField(blank=True, null=True)
    ConductorIndicator=models.BooleanField()
    objects=models.GeoManager()    
    def __unicode__(self):
        return self.Name
    class Meta:
        db_table=u'coopgismaterial'
        app_label='djangoproject'
    def GetOrCreate(self, Name, Description='', ConductorIndicator=False):
        try:
            New=Material.objects.get(Name=Name)
            return New
        except:
            pass
        New=Material()
        New.Name=Name
        New.Description=Description
        New.ConductorIndicator=ConductorIndicator
        New.save()
        return New        

class PartEach(models.Model):
    """PartEach holds a list of ways that a part can be measured (eg inch, each, mile, etc)"""
    Name=models.CharField(max_length=250)
    Description=models.TextField()
    objects=models.GeoManager()
    class Meta:
        db_table=u'coopgisparteach'
        app_label='djangoproject'
    def GetOrCreate(self, Name, Description=''):
        try:
            New=PartEach.objects.get(Name=Name)
            return New
        except:
            pass
        New=PartEach()
        New.Name=Name
        New.Description=Description
        New.save()
        return New        

        
class Part(models.Model):
    """Part holds a list of parts.  Parts make up Compatible Units."""
    Name=models.CharField(max_length=250)
    Number=models.CharField(max_length=250)
    DiscontinueDate=models.DateField(null=True, blank=True)
    PartEach=models.ForeignKey('PartEach', on_delete=models.PROTECT)
    Description=models.TextField()
    objects=models.GeoManager()
    class Meta:
        db_table=u'coopgispart'
        app_label='djangoproject'
    def GetOrCreate(self, Name, Number, DiscontinueDate=None, PartEach=None, Description=''):
        try:
            New=Part.objects.get(Number=Number)
            return New
        except:
            pass
        New=Part()
        New.Name=Name
        New.Number=Number
        New.DiscontinueDate=DiscontinueDate
        New.PartEach=PartEach
        New.Description=Description
        New.save()
        return New        

class PartSupplier(models.Model):
    """List of Sources of Part Info/Prices (probably from CIS to start)"""
    Name=models.CharField(max_length=250)
    Description=models.TextField()
    objects=models.GeoManager()
    class Meta:
        db_table=u'coopgispartsupplier'
        app_label='djangoproject'
    def GetOrCreate(self, Name, Description=''):
        try:
            New=PartSupplier.objects.get(Name=Name)
            return New
        except:
            pass
        New=PartSupplier()
        New.Name=Name
        New.Description=Description
        New.save()
        return New        


class PartCost(models.Model):
    """PartCost holds a list of prices for parts."""
    Part=models.ForeignKey('Part', on_delete=models.PROTECT)
    Price=models.FloatField()
    Date=models.DateField()
    Description=models.TextField()
    PartSupplier=models.ForeignKey('PartSupplier', null=True, blank=True, on_delete=models.SET_NULL)    
    objects=models.GeoManager()
    class Meta:
        db_table=u'coopgispartcost'
        app_label='djangoproject'
    def GetOrCreate(self, Part, Price, Date, Comment='', PartSupplier=None):
        try:
            New=PartCost.objects.get(Name=Name)
            return New
        except:
            pass
        New=PartCost()
        New.Name=Name
        New.Description=Description
        New.Date=Date
        New.Comment=Comment
        New.PartSupplier=PartSupplier
        New.save()
        return New        

        
class Voltage(models.Model):
    """Voltage is a list of possible voltages we have"""
    Name=models.CharField(max_length=250)
    Description=models.TextField()
    Value=models.FloatField()
    TransmissionIndicator=models.BooleanField()
    PrimaryIndicator=models.BooleanField()
    SecondaryIndicator=models.BooleanField()
    ServiceIndicator=models.BooleanField()
    ResidesOnServerIndicator=models.BooleanField()
    objects=models.GeoManager()
    def __unicode__(self):
        return self.Name
    class Meta:
        db_table=u'coopgisvoltage'
        app_label='djangoproject'
    def GetOrCreate(self, Name, Value, PrimaryIndicator=False,
                    SecondaryIndicator=False, ServiceIndicator=False,
                    TransmissionIndicator=False, Description=''):
        try:
            New=Voltage.objects.get(Name=Name)
            return New
        except:
            pass
        New=Voltage()
        New.Name=Name
        New.Description=Description
        New.Value=Value
        New.PrimaryIndicator=PrimaryIndicator
        New.SecondaryIndicator=SecondaryIndicator
        New.ServiceIndicator=ServiceIndicator
        New.TransmissionIndicator=TransmissionIndicator
        New.save()
        return New     
    def GetIndexWhenReverseSorted(self):
        Objects=Voltage.objects.all().order_by('-id')
        i = 0
        while(True):
            if(Objects[i] == self):
                return i
            i = i + 1
    def GetCommandidData(self):
        if(self.ResidesOnServerIndicator):
            return self.id, None
        return None, self.GetIndexWhenReverseSorted()

        
class CompatibleUnitCategory(models.Model):
    """CompatibleUnitCategory is a list of categories (Operations, Maintenance, Capital)"""
    Name=models.CharField(max_length=250)
    Description=models.TextField()
    objects=models.GeoManager()
    def __unicode__(self):
        return self.Name
    class Meta:
        db_table=u'coopgiscompatibleunitcategory'
        app_label='djangoproject'
    def GetOrCreate(self, Name, Description=''):
        try:
            New=CompatibleUnitCategory.objects.get(Name=Name)
            return New
        except:
            pass
        New=CompatibleUnitCategory()
        New.Name=Name
        New.Description=Description
        New.save()
        return New        

class CompatibleUnit(models.Model):
    """CompatibleUnit is a List of all possible Assembly Compatible Units that we use."""
    Name=models.CharField(max_length=250, unique=True)
    Description=models.TextField(null=True, blank=True)
    GISIndicator=models.NullBooleanField(null=True, blank=True) #Indicates Compatible Units that are used by the GIS
    CISIndicator=models.NullBooleanField(null=True, blank=True)  #Indicates Compatible Units that match ones in the CIS    
    CompatibleUnitCategory=models.ForeignKey('CompatibleUnitCategory', null=True, blank=True, on_delete=models.PROTECT)
    LaborHours=models.FloatField()   
    #The following fields are specific to electric equipment    
    KVA=models.FloatField(null=True, blank=True)
    KVAR=models.FloatField(null=True, blank=True)
    InputVoltage=models.ForeignKey('Voltage', null=True, blank=True, on_delete=models.PROTECT)
    FirstOutputVoltage=models.ForeignKey('Voltage', related_name="CompatibleFirstUnitOutputVoltage", null=True, blank=True, on_delete=models.PROTECT)
    SecondOutputVoltage=models.ForeignKey('Voltage', related_name="CompatibleUnitSecondOutputVoltage", null=True, blank=True, on_delete=models.PROTECT)
    MaximumContinousAmp=models.FloatField(null=True, blank=True)
    Wattage=models.FloatField(null=True, blank=True)
    #The following are specific to Poles (or possibly other equipment with heights)
    Height=models.CharField(max_length=250, null=True, blank=True)
    Class=models.CharField(max_length=250, null=True, blank=True)
    #The following fields identify whether a compatible unit should be placed in a Span or Station
    StationIndicator=models.BooleanField()
    SpanIndicator=models.BooleanField()
    #Compatible Units are normally installed either overhead or underground, with occasional exceptions
    NormallyOverHeadIndicator=models.BooleanField()
    NormallyUndergroundIndicator=models.BooleanField()
    #The following is an attribute that is used only by conductors
    ConductorNumberOfWires=models.IntegerField(null=True, blank=True) #Number of wires in a conductor (1 for most, 2 for duplex, 3 for tri, etc.)
    #The following fields identify Compatible Unit Categories
    #What function a device does is defined by these fields
    #SpanAssemblies:
    ConductorIndicator=models.BooleanField()
    ConduitIndicator=models.BooleanField()
    SpanGuyIndicator=models.BooleanField()
    #StationAssemblies:
    CapacitorIndicator=models.BooleanField()
    CutOutIndicator=models.BooleanField()
    FeederIndicator=models.BooleanField()
    GroundIndicator=models.BooleanField()
    LightIndicator=models.BooleanField()
    LightningArrestorIndicator=models.BooleanField()
    OpenPointIndicator=models.BooleanField()
    VaultIndicator=models.BooleanField()  #Includes Underground Stations (secondary vaults and pedestals)
    MiscellaneousEquipmentIndicator=models.BooleanField()
    PoleIndicator=models.BooleanField()
    RecloserIndicator=models.BooleanField()
    RegulatorIndicator=models.BooleanField()
    MeterIndicator=models.BooleanField()
    ServicePointIndicator=models.BooleanField()
    SubstationIndicator=models.BooleanField()
    SwitchIndicator=models.BooleanField()
    TransformerIndicator=models.BooleanField()
    URDMarkerIndicator=models.BooleanField()  #Represents a Station that acts as a vertex for underground without a break in the wire
    #The following fields identify Compatible Unit Staker Categories
    StakerPoleIndicator=models.BooleanField()
    StakerTransformerIndicator=models.BooleanField()
    StakerMiscEquipmentIndicator=models.BooleanField()
    StakerGroundIndicator=models.BooleanField()
    StakerGuyGuyIndicator=models.BooleanField()
    StakerGuyAnchorIndicator=models.BooleanField()
    StakerGuyMarkerIndicator=models.NullBooleanField(db_column='stakerguymarkerindicator', null=True, blank=True)
    StakerUnitIndicator=models.NullBooleanField(null=True, blank=True)
    StakerSpanAssemblyIndicator=models.NullBooleanField(null=True, blank=True)
    objects=models.GeoManager()
    def __unicode__(self):
        return self.Name
    def StringDetailed(self):
        """StringDetailed at the Compatible Unit level is used to make certain type of units stand out"""
        StringList=[]
        if(self.MeterIndicator):
            StringList.append('Meter')
        if(self.SubstationIndicator):
            StringList.append('Substation')
        if(self.SwitchIndicator):
            StringList.append('Switch')
        String=' '.join(StringList)
        return str(self) + ': ' + String
    class Meta:
        db_table=u'coopgiscompatibleunit'
        app_label='djangoproject'
        ordering=('Name',)
    @staticmethod
    def GetOrModify(Name, Description='', GISIndicator=False, CISIndicator=False, CompatibleUnitCategory=None, 
                    KVA=None, KVAR=None, InputVoltage=None, FirstOutputVoltage=None, SecondOutputVoltage=None,
                    MaximumContinousAmp=None, Wattage=None, ConductorNumberOfWires=None,
                    Height=None, Class=None, LaborHours=0.0, StationIndicator=False, SpanIndicator=False,
                    NormallyOverHeadIndicator=False, NormallyUndergroundIndicator=False,
                    ConductorIndicator=False, ConduitIndicator=False,
                    CapacitorIndicator=False, CutOutIndicator=False, FeederIndicator=False, 
                    GroundIndicator=False, LightIndicator=False, LightningArrestorIndicator=False,
                    OpenPointIndicator=False, 
                    MiscellaneousEquipmentIndicator=False, PoleIndicator=False,
                    RecloserIndicator=False, RegulatorIndicator=False, 
                    MeterIndicator=False, ServicePointIndicator=False, SpanGuyIndicator=False,
                    SubstationIndicator=False, SwitchIndicator=False, URDMarkerIndicator=False,
                    TransformerIndicator=False, VaultIndicator=False,
                    StakerPoleIndicator=False, 
                    StakerTransformerIndicator=False, StakerMiscEquipmentIndicator=False,
                    StakerGroundIndicator=False, StakerGuyGuyIndicator=False,
                    StakerGuyAnchorIndicator=False, StakerGuyMarkerIndicator=False,
                    StakerUnitIndicator=False, StakerSpanAssemblyIndicator=False):
        """GetOrModify returns a new instance of the object or edits an existing instance, based on a specific field (such as Name"""
        try:
            New=CompatibleUnit.objects.get(Name=Name)
            if((SpanIndicator and StationIndicator) or (not SpanIndicator and not StationIndicator)):
	        raise("Span and Station Indicator cannot match for a Compatible Unit")
            New.Description=Description
            New.GISIndicator=GISIndicator
            New.CISIndicator=CISIndicator
            New.CompatibleUnitCategory=CompatibleUnitCategory
            New.StationIndicator=StationIndicator
            New.LaborHours=LaborHours
            if(not New.LaborHours):
                New.LaborHours=0.0
            New.KVA=KVA
            New.KVAR=KVAR
            New.InputVoltage=InputVoltage
            New.FirstOutputVoltage=FirstOutputVoltage
            New.SecondOutputVoltage=SecondOutputVoltage
            New.MaximumContinousAmp=MaximumContinousAmp
            New.Wattage=Wattage
            New.ConductorNumberOfWires=ConductorNumberOfWires
            New.Height=Height
            New.Class=Class
	    New.SpanIndicator=SpanIndicator
	    New.StationIndicator=StationIndicator
	    New.NormallyOverHeadIndicator=NormallyOverHeadIndicator
	    New.NormallyUndergroundIndicator=NormallyUndergroundIndicator
            New.ConductorIndicator=ConductorIndicator
            New.ConduitIndicator=ConduitIndicator
            New.CapacitorIndicator=CapacitorIndicator
            New.CutOutIndicator=CutOutIndicator
            New.FeederIndicator=FeederIndicator
            New.GroundIndicator=GroundIndicator
            New.LightIndicator=LightIndicator
            New.LightningArrestorIndicator=LightningArrestorIndicator
            New.OpenPointIndicator=OpenPointIndicator
            New.MiscellaneousEquipmentIndicator=MiscellaneousEquipmentIndicator
            New.PoleIndicator=PoleIndicator
            New.RecloserIndicator=RecloserIndicator
            New.RegulatorIndicator=RegulatorIndicator
            New.MeterIndicator=MeterIndicator
            New.ServicePointIndicator=ServicePointIndicator
            New.SpanGuyIndicator=SpanGuyIndicator
            New.SubstationIndicator=SubstationIndicator
            New.SwitchIndicator=SwitchIndicator
            New.TransformerIndicator=TransformerIndicator
            New.URDMarkerIndicator=URDMarkerIndicator
            New.VaultIndicator=VaultIndicator
            New.StakerPoleIndicator=StakerPoleIndicator
            New.StakerTransformerIndicator=StakerTransformerIndicator
            New.StakerMiscEquipmentIndicator=StakerMiscEquipmentIndicator
            New.StakerGroundIndicator=StakerGroundIndicator
            New.StakerGuyGuyIndicator=StakerGuyGuyIndicator
            New.StakerGuyMarkerIndicator=StakerGuyMarkerIndicator
            New.StakerGuyAnchorIndicator=StakerGuyAnchorIndicator
            New.StakerUnitIndicator=StakerUnitIndicator
            New.StakerSpanAssemblyIndicator=StakerSpanAssemblyIndicator
            New.save()
            return New
        except:
            pass
	if((SpanIndicator and StationIndicator) or (not SpanIndicator and not StationIndicator)):
	    raise(Exception("Check SpanIndicator OR StationIndicator.  ONE of those two must be checked to create a unit."))
        New=CompatibleUnit()
        New.Name=Name    
        New.Description=Description
        New.GISIndicator=GISIndicator
        New.CISIndicator=CISIndicator
        New.CompatibleUnitCategory=CompatibleUnitCategory
        New.StationIndicator=StationIndicator
        New.LaborHours=LaborHours
        if(not New.LaborHours):
            New.LaborHours=0.0
        New.KVA=KVA
        New.KVAR=KVAR
        New.InputVoltage=InputVoltage
        New.FirstOutputVoltage=FirstOutputVoltage
        New.SecondOutputVoltage=SecondOutputVoltage
        New.MaximumContinousAmp=MaximumContinousAmp
        New.Wattage=Wattage
        New.ConductorNumberOfWires=ConductorNumberOfWires
        New.Height=Height
        New.Class=Class
	New.SpanIndicator=SpanIndicator
	New.StationIndicator=StationIndicator
	New.NormallyOverHeadIndicator=NormallyOverHeadIndicator
	New.NormallyUndergroundIndicator=NormallyUndergroundIndicator
        New.ConductorIndicator=ConductorIndicator
        New.ConduitIndicator=ConduitIndicator
        New.CapacitorIndicator=CapacitorIndicator
        New.CutOutIndicator=CutOutIndicator
        New.FeederIndicator=FeederIndicator
        New.GroundIndicator=GroundIndicator
        New.LightIndicator=LightIndicator
        New.LightningArrestorIndicator=LightningArrestorIndicator
        New.OpenPointIndicator=OpenPointIndicator
        New.MiscellaneousEquipmentIndicator=MiscellaneousEquipmentIndicator
        New.PoleIndicator=PoleIndicator
        New.RecloserIndicator=RecloserIndicator
        New.RegulatorIndicator=RegulatorIndicator
        New.MeterIndicator=MeterIndicator
        New.ServicePointIndicator=ServicePointIndicator
        New.SpanGuyIndicator=SpanGuyIndicator
        New.SubstationIndicator=SubstationIndicator
        New.SwitchIndicator=SwitchIndicator
        New.TransformerIndicator=TransformerIndicator
        New.URDMarkerIndicator=URDMarkerIndicator
        New.VaultIndicator=VaultIndicator
        New.StakerPoleIndicator=StakerPoleIndicator
        New.StakerTransformerIndicator=StakerTransformerIndicator
        New.StakerMiscEquipmentIndicator=StakerMiscEquipmentIndicator
        New.StakerGroundIndicator=StakerGroundIndicator
        New.StakerGuyGuyIndicator=StakerGuyGuyIndicator
        New.StakerGuyMarkerIndicator=StakerGuyMarkerIndicator
        New.StakerGuyAnchorIndicator=StakerGuyAnchorIndicator
        New.StakerUnitIndicator=StakerUnitIndicator
        New.StakerSpanAssemblyIndicator=StakerSpanAssemblyIndicator
        New.save()
        return New

class PartMap(models.Model):
    """PartMap creates a ManyToMany relationship between Compatible Unit and Part"""
    Part=models.ForeignKey('Part', on_delete=models.PROTECT)
    CompatibleUnit=models.ForeignKey('CompatibleUnit', on_delete=models.PROTECT)
    objects=models.GeoManager()
    class Meta:
        db_table=u'coopgispartmap'
        app_label='djangoproject'

class LightLampType(models.Model):
    """LightLampType is a list of possible lamp types for lights"""
    Name=models.CharField(max_length=250)
    Description=models.TextField(blank=True, null=True)
    objects=models.GeoManager()
    def __unicode__(self):
        return self.Name
    class Meta:
        db_table=u'coopgislightlamptype'
        app_label='djangoproject'
    def GetOrCreate(self, Name, Description=''):
        try:
            New=LightLampType.objects.get(Name=Name)
            return New
        except:
            pass
        New=LightLampType()
        New.Name=Name
        New.Description=Description
        New.save()
        return New

class LightFixtureType(models.Model):
    """LightFixtureType is a list of possible types for light fixtures"""
    Name=models.CharField(max_length=250)
    Description=models.TextField(blank=True, null=True)
    objects=models.GeoManager()
    def __unicode__(self):
        return self.Name
    class Meta:
        db_table=u'coopgislightfixturetype'
        app_label='djangoproject'
    def GetOrCreate(self, Name, Description=''):
        try:
            New=LightFixtureType.objects.get(Name=Name)
            return New
        except:
            pass
        New=LightFixtureType()
        New.Name=Name
        New.Description=Description
        New.save()
        return New
    
class TransformerWindingType(models.Model):
    """TransformerWindingType is a list of possible Transformer Winding Types"""
    Name=models.CharField(max_length=250)
    Description=models.TextField(blank=True, null=True)
    objects=models.GeoManager()
    def __unicode__(self):
        return self.Name
    class Meta:
        db_table=u'coopgistransformerwindingtype'
        app_label='djangoproject'
    def GetOrCreate(self, Name, Description=''):
        try:
            New=TransformerWindingType.objects.get(Name=Name)
            return New
        except:
            pass
        New=TransformerWindingType()
        New.Name=Name
        New.Description=Description
        New.save()
        return New
        
class PoleRightOfWayStatus(models.Model):
    """PoleRightOfWayStatus includes generic descriptions of possible right of way status"""
    Name=models.CharField(max_length=250)
    Description=models.TextField()
    objects=models.GeoManager()
    def __unicode__(self):
        return self.Name
    class Meta:
        db_table=u'coopgispolerightofwaystatus'
        app_label='djangoproject'
    def GetOrCreate(self, Name, Description=''):
        try:
            New=PoleRightOfWayStatus.objects.get(Name=Name)
            return New
        except:
            pass
        New=PoleRightOfWayStatus()
        New.Name=Name
        New.Description=Description
        New.save()
        return New

class MeterServiceType(models.Model):
    """MeterServiceType lists possible service types (Residential, Commercial...)"""
    Name=models.CharField(max_length=250)
    Description=models.TextField()
    objects=models.GeoManager()
    def __unicode__(self):
        return self.Name
    class Meta:
        db_table=u'coopgismeterservicetype'
        app_label='djangoproject'
    def GetOrCreate(self, Name, Description=''):
        try:
            New=MeterServiceType.objects.get(Name=Name)
            return New
        except:
            pass
        New=MeterServiceType()
        New.Name=Name
        New.Description=Description
        New.save()
        return New
                    
class Fuse(models.Model):
    Name=models.CharField(max_length=250)
    Description=models.TextField()
    AmpRating=models.FloatField(blank=True, null=True)
    objects=models.GeoManager()
    def __unicode__(self):
        return self.Name
    class Meta:
        db_table=u'coopgisfuse'
        app_label='djangoproject'
    def GetOrCreate(self, Name, Description='', AmpRating=None):
        try:
            New=Fuse.objects.get(Name=Name)
            return New
        except:
            pass
        New=Fuse()
        New.Name=Name
        New.Description=Description
        New.AmpRating=AmpRating
        New.save()
        return New

class MeterForm(models.Model):
    Name=models.CharField(max_length=250)
    Description=models.TextField()
    objects=models.GeoManager()
    def __unicode__(self):
        return self.Name
    class Meta:
        db_table=u'coopgismeterform'
        app_label='djangoproject'
    def GetOrCreate(self, Name, Description=''):
        try:
            New=MeterForm.objects.get(Name=Name)
            return New
        except:
            pass
        New=MeterForm()
        New.Name=Name
        New.Description=Description
        New.save()
        return New

class Assembly(models.Model):
    """Assembly is all of the Compatible Units we have deployed."""
    Station=models.ForeignKey('Station', null=True, blank=True, on_delete=models.PROTECT)  #Represents where the unit is if a point
    Span=models.ForeignKey('Span', null=True, blank=True, on_delete=models.PROTECT) #represents where the unit is if a line
    CompatibleUnit=models.ForeignKey('CompatibleUnit', on_delete=models.PROTECT)
    Rotation=models.FloatField(db_column='rotation')
    PhaseAIndicator=models.BooleanField(db_column='phaseaindicator')
    PhaseBIndicator=models.BooleanField(db_column='phasebindicator')
    PhaseCIndicator=models.BooleanField(db_column='phasecindicator')
    PhaseNeutralIndicator=models.BooleanField(db_column='phaseneutralindicator')
    CircuitNumber=models.IntegerField(db_column='circuitnumber')   #CircuitNumber out of the substation the assembly is fed off of
    TagNumber=models.CharField(db_column='tagnumber',max_length=250)
    PhysicalAddress=models.CharField(db_column='physicaladdress',max_length=250, blank=True, null=True)
    Description=models.TextField(db_column='description')
    Manufacturer=models.ForeignKey('Company', blank=True, null=True, on_delete=models.PROTECT)
    Quantity=models.IntegerField(db_column='quantity')
    OverHeadIndicator=models.BooleanField(db_column='overheadindicator')  #Will normally be the same as the CompatibleUnit NormallyOverHeadIndicator but not always
    UndergroundIndicator=models.BooleanField(db_column='undergroundindicator') #Will normally be the same as the CompatibleUnit NormallyOverHeadIndicator but not always
    OpenIndicator=models.BooleanField(db_column='openindicator')
    IdleIndicator=models.NullBooleanField(db_column='idleindicator',blank=True, null=True)
    PrimaryIndicator=models.BooleanField(db_column='primaryindicator')
    SecondaryIndicator=models.BooleanField(db_column='secondaryindicator')
    ServiceIndicator=models.BooleanField(db_column='serviceindicator')
    ActualVoltage=models.ForeignKey('Voltage', null=True, blank=True, on_delete=models.PROTECT)
    AssemblyOwner=models.ForeignKey('AssemblyOwner', on_delete=models.PROTECT)
    PutIntoServiceDate=models.DateField(db_column='putintoservicedate',blank=True, null=True)
    SerialNumber=models.CharField(db_column='serialnumber', max_length=250, blank=True)
    OldMapNumber=models.CharField(db_column='oldmapnumber', max_length=250, blank=True)
    MapNumber=models.IntegerField(db_column='mapnumber', null=True, blank=True) #meters and lights will have this field populated
    BypassIndicator=models.NullBooleanField(db_column='bypassindicator', null=True, blank=True)
    #Must have Conductor Indicator for these fields to have meaning
    ConductorPlacementStartStation=models.ForeignKey('ConductorPlacement', blank=True, null=True, related_name="AssemblyConductorPlacementStartStation", on_delete=models.PROTECT)
    ConductorPlacementEndStation=models.ForeignKey('ConductorPlacement', blank=True, null=True, related_name="AssemblyConductorPlacementEndStation", on_delete=models.PROTECT)
    #Must have CutOut Indicator for these fields to have meaning
    CutOutFuse=models.ForeignKey('Fuse', null=True, blank=True, on_delete=models.PROTECT)
    TransformerCutOutIndicator=models.NullBooleanField(db_column='transformercutoutindicator', null=True, blank=True)
    #Must have Recloser Indicator for these fields to have meaning
    RecloserMaximumContinousAmp=models.FloatField(db_column='reclosermaximumcontinuousamp', null=True, blank=True)
    RecloserMaximumIntermittentAmp=models.FloatField(db_column='reclosermaximumintermittentamp', null=True, blank=True)
    RecloserLinkRating=models.FloatField(db_column='recloserlinkrating', null=True, blank=True)
    #Must have Transformer Indicator for these fields to have meaning
    TransformerPrimaryWinding=models.ForeignKey('TransformerWindingType', null=True, blank=True, related_name="AssemblyTransformerPrimaryWinding", on_delete=models.PROTECT)
    TransformerSecondaryWinding=models.ForeignKey('TransformerWindingType', null=True, blank=True, related_name="AssemblyTransformerSecondaryWinding", on_delete=models.PROTECT)
    TransformerCompletelySelfProtectedIndicator=models.NullBooleanField(db_column='transformercompletelyselfprotectedindicator', null=True, blank=True)
    TransformerSecondaryHighVoltage=models.ForeignKey('Voltage', null=True, blank=True, related_name="TransformerSecondaryHighVoltage", on_delete=models.PROTECT)
    TransformerSecondaryLowVoltage=models.ForeignKey('Voltage', null=True, blank=True, related_name="TransformerSecondaryLowVoltage", on_delete=models.PROTECT)    
    #Must have Light Indicator for these fields to have meaning
    LightLampType=models.ForeignKey('LightLampType', null=True, blank=True, on_delete=models.PROTECT)
    LightFixtureType=models.ForeignKey('LightFixtureType', null=True, blank=True, on_delete=models.PROTECT)
    #Must have Pole Indicator for these fields to have meaning
    PoleRightOfWayStatus=models.ForeignKey('PoleRightOfWayStatus', blank=True, null=True, on_delete=models.PROTECT)
    PoleLightIndicator=models.NullBooleanField(db_column='polelightindicator', blank=True, null=True)
    PoleGuyIndicator=models.NullBooleanField(db_column='poleguyindicator', blank=True, null=True)    #Deprecated, need to replace this with StubIndicator, move values over (after inventory collection is done...)
    PoleStubIndicator=models.NullBooleanField(db_column='polestubindicator', blank=True, null=True)
    PoleMeterIndicator=models.NullBooleanField(db_column='polemeterindicator', blank=True, null=True)
    #Must have the Recloser Indicator for these fields to have meaning
    RecloserType=models.CharField(db_column='reclosertype', max_length=250, blank=True, null=True)
    RecloserTripSetting=models.TextField(db_column='reclosertripsetting')
    #Must have the Regulator Indicator for these fields to have meaning
    RegulatorCurrentTransformerRating=models.FloatField(db_column='regulatorcurrenttransformerrating', blank=True, null=True)
    RegulatorPanelType=models.CharField(db_column='regulatorpaneltype', max_length=250, null=True, blank=True)
    RegulatorSetting=models.IntegerField(db_column='regulatorsetting', blank=True, null=True)
    #Must have MeterIndicator for these fields to have meaning, can be blank if no link created between a meter and station
    MeterDescription=models.TextField(db_column='meterdescription')
    MeterLocationNumberFromCIS=models.CharField(db_column='meterlocationnumberfromcis', max_length=250)
    MeterServiceType=models.ForeignKey('MeterServiceType', null=True, blank=True)
    MeterDCSINumber=models.CharField(db_column='meterdcsinumber', max_length=250, blank=True)
    MeterNumber=models.CharField(db_column='meternumber', max_length=250, blank=True)
    MeterForm=models.ForeignKey('MeterForm', blank=True, null=True)
    MeterOnPoleIndicator=models.BooleanField(db_column='meteronpoleindicator')
    MeterActiveIndicator=models.BooleanField(db_column='meteractiveindicator')
    #Must have Substation Indicator for these fields to have meaning
    SubstationName=models.CharField(db_column='substationname', max_length=250, null=True, blank=True)
    SubstationSourceRegulatedIndicator=models.NullBooleanField(db_column='substationsourceregulatedindicator', null=True, blank=True)
    SubstationLoadConnection=models.CharField(db_column='substationloadconnection', max_length=250, blank=True, null=True)
    SubstationVoltage=models.ForeignKey('Voltage', blank=True, null=True, related_name="SubstationVoltage")
    #Must have Bypass Indicator for these fields to have meaning
    BypassAssembly=models.ForeignKey('Assembly', blank=True, null=True, related_name='BypassAssemblyRelatedName')
    #The following are Meta data/CRUD related Fields
    CreateDate=models.DateField(db_column='createdate', blank=True, null=True)
    LastModifyDate=models.DateField(db_column='lastmodifydate', blank=True, null=True)
    ResidesOnServerIndicator=models.NullBooleanField(db_column='residesonserverindicator', null=True, blank=True)
    #Network Connectivity Related Fields:
    UpstreamAssembly=models.ForeignKey('Assembly', blank=True, null=True, related_name="UpstreamAssemblyRelatedName", on_delete=models.PROTECT)  #Upstream towards Substation
    UpstreamGeneratorAssembly=models.ForeignKey('Assembly', blank=True, null=True, related_name="UpstreamGeneratorAssemblyRelatedName", on_delete=models.PROTECT) #Upstream towards generator
    InstallStatus=models.ForeignKey('InstallStatus', null=True, blank=True) #Existing, Install, Remove
    StakerWorkOrder=models.ForeignKey('StakerWorkOrder', null=True, blank=True, on_delete=models.PROTECT)
    StakerLength=models.FloatField(db_column='stakerlength', null=True, blank=True) #Calculated field used during Staker Process to store the length of an assembly
    StakerStationOverride=models.ForeignKey('Station', null=True, blank=True, related_name='StakerStationOverride', on_delete=models.PROTECT) #Allows an assembly to appear on a staker report with any station desired
    StakerRecipeNumber=models.IntegerField(db_column='stakerrecipenumber', null=True, blank=True)
    TransformerBank=models.ForeignKey('TransformerBank', db_column='transformerbank', null=True, blank=True, on_delete=models.PROTECT)
    CreateCommand=models.ForeignKey('Command', null=True, blank=True, on_delete=models.SET_NULL)
    objects=models.GeoManager()
    def __unicode__(self):
        return str(self.CompatibleUnit)
    class Meta:
        db_table=u'coopgisassembly'
        app_label='djangoproject'
    @staticmethod
    def GetOrCreate(CompatibleUnit, Quantity, Station=None, Span=None,
                    Rotation=0,PhysicalAddress=None,
                    PhaseAIndicator=False, PhaseBIndicator=False, PhaseCIndicator=False, PhaseNeutralIndicator=False,
                    CircuitNumber=1, upstreamAssembly=None, upstreamGeneratorAssembly=None, assemblyOwner=None, PutIntoServiceDate=None,
                    TagNumber='', Description='', Manufacturer=None,
                    OverHeadIndicator=False, UndergroundIndicator=False, 
                    PrimaryIndicator=False, SecondaryIndicator=False, ServiceIndicator=False,
                    IdleIndicator=False, 
                    ConductorPlacementStartStation=None, ConductorPlacementEndStation=None,
                    ActualVoltage=None, SerialNumber='',
                    TransformerPrimaryWinding=None, TransformerSecondaryWinding=None,
                    RecloserMaximumContinousAmp=None, RecloserMaximumIntermittentAmp=None,
                    RecloserLinkRating=None,
                    LightLampType=None, LightFixtureType=None,
                    PoleRightOfWayStatus=None, PoleLightIndicator=False, PoleGuyIndicator=False, PoleStubIndicator=False, PoleMeterIndicator=False,
                    RecloserType=None, RecloserTripSetting='',
                    RegulatorCurrentTransformerRating=None, RegulatorPanelType='', RegulatorSetting=None,
                    CutOutFuse=None, OldMapNumber='', MapNumber='',
                    SubstationName='', SubstationSourceRegulatedIndicator=False, SubstationLoadConnection='',
                    OpenIndicator=False,
                    TransformerCompletelySelfProtectedIndicator=False, TransformerSecondaryHighVoltage=None,
                    TransformerSecondaryLowVoltage=None,
                    MeterDescription='', MeterServiceType=None,
                    MeterDCSINumber='', MeterNumber='', meterForm=None,
                    MeterOnPoleIndicator=False, 
                    MeterActiveIndicator=False, SubstationVoltage=None,
                    CreateDate=None, LastModifyDate=None, CreateCommand=None, InstallStatus=None, StakerWorkOrder=None,
                    StakerStationOverride=None, StakerRecipeNumber=None, transformerBank=None):
        New=Assembly()
        New.CompatibleUnit=CompatibleUnit
        New.Quantity=Quantity
        New.Station=Station
        New.Span=Span
        New.UpstreamAssembly=upstreamAssembly
        New.UpstreamGeneratorAssembly=upstreamGeneratorAssembly
        New.Rotation=Rotation
        New.PhaseAIndicator=PhaseAIndicator
        New.PhaseBIndicator=PhaseBIndicator
        New.PhaseCIndicator=PhaseCIndicator
        New.PhaseNeutralIndicator=PhaseNeutralIndicator
        New.CircuitNumber=CircuitNumber
        New.PhysicalAddress=PhysicalAddress
        if(assemblyOwner):
            New.AssemblyOwner=assemblyOwner
        else:
            assemblyOwner=AssemblyOwner()
            assemblyOwner=assemblyOwner.GetOrCreate("Tri-County Electric COOP")
            New.AssemblyOwner=assemblyOwner
        New.TagNumber=TagNumber
        New.PutIntoServiceDate=PutIntoServiceDate
        New.SerialNumber=SerialNumber
        New.Description=Description 
        if(not Manufacturer):
            Manufacturer = None
        New.Manufacturer=Manufacturer
        New.OverHeadIndicator=OverHeadIndicator
        New.UndergroundIndicator=UndergroundIndicator
        if(not New.OverHeadIndicator and not New.UndergroundIndicator):
            New.OverHeadIndicator=CompatibleUnit.NormallyOverHeadIndicator
            New.UndergroundIndicator=CompatibleUnit.NormallyUndergroundIndicator
        New.PrimaryIndicator=PrimaryIndicator
        New.SecondaryIndicator=SecondaryIndicator
        New.ServiceIndicator=ServiceIndicator
        New.IdleIndicator=IdleIndicator
        New.ConductorPlacementStartStation=ConductorPlacementStartStation
        New.ConductorPlacementEndStation=ConductorPlacementEndStation
        New.CutOutFuse=CutOutFuse
        New.RecloserMaximumContinousAmp=RecloserMaximumContinousAmp
        New.RecloserMaximumIntermittentAmp=RecloserMaximumIntermittentAmp
        New.RecloserLinkRating=RecloserLinkRating
        New.TransformerPrimaryWinding=TransformerPrimaryWinding
        New.TransformerSecondaryWinding=TransformerSecondaryWinding
        New.TransformerCompletelySelfProtectedIndicator=TransformerCompletelySelfProtectedIndicator
        New.TransformerSecondaryHighVoltage=TransformerSecondaryHighVoltage
        New.TransformerSecondaryLowVoltage=TransformerSecondaryLowVoltage
        New.LightLampType=LightLampType
        New.LightFixtureType=LightFixtureType
        New.PoleRightOfWayStatus=PoleRightOfWayStatus
        New.PoleLightIndicator=PoleLightIndicator
        New.PoleGuyIndicator=PoleGuyIndicator
        New.PoleStubIndicator=PoleStubIndicator
        New.PoleMeterIndicator=PoleMeterIndicator
        New.RecloserType=RecloserType
        New.RecloserTripSetting=RecloserTripSetting
        New.RegulatorCurrentTransformerRating=RegulatorCurrentTransformerRating
        New.RegulatorPanelType=RegulatorPanelType
        New.RegulatorSetting=RegulatorSetting
        New.OpenIndicator=OpenIndicator
        New.MeterDescription=MeterDescription
        New.MeterServiceType=MeterServiceType
        New.MeterForm=meterForm
        New.MeterOnPoleIndicator=MeterOnPoleIndicator
        New.MeterActiveIndicator=MeterActiveIndicator
        New.MeterNumber=MeterNumber
        New.MeterDCSINumber=MeterDCSINumber
        New.OldMapNumber=OldMapNumber   #FIXME Add check for meter map numbers to ensure they are between 100,000 and 599,999 and that light map number are between 600,000 and 999,999
        try:
            New.MapNumber=int(MapNumber)
        except ValueError: 
            if New.CompatibleUnit.MeterIndicator:
                Assemblies = Assembly.objects.filter(CompatibleUnit__MeterIndicator=True).exclude(MapNumber__isnull=True).order_by('-MapNumber')
                HighestMapNumber = None
                for i in Assemblies:
                    try:
                        HighestMapNumber = int(i.MapNumber)
                        break
                    except ValueError:
                        continue
                if HighestMapNumber:
                    New.MapNumber = HighestMapNumber + 1
                else:
                    New.MapNumber = 100001
            elif New.CompatibleUnit.LightIndicator:
                Assemblies = Assembly.objects.filter(CompatibleUnit__LightIndicator=True).exclude(MapNumber__isnull=True).order_by('-MapNumber')
                HighestMapNumber = None
                for i in Assemblies:
                    try:
                        HighestMapNumber = int(i.MapNumber)
                        break
                    except ValueError:
                        continue
                if HighestMapNumber:
                    New.MapNumber = HighestMapNumber + 1
                else:
                    New.MapNumber = 700001
        New.SubstationName=SubstationName
        New.SubstationSourceRegulatedIndicator=SubstationSourceRegulatedIndicator
        New.SubstationLoadConnection=SubstationLoadConnection
        New.SubstationVoltage=SubstationVoltage
        New.ResidesOnServerIndicator=djangoproject.settings.COOPGISServerIndicator
        if(CreateDate):
            New.CreateDate=CreateDate
        else:
            New.CreateDate=datetime.date.today()
        if(LastModifyDate):
            New.LastModifyDate=LastModifyDate
        else:
            New.LastModifyDate=datetime.date.today()
        New.InstallStatus=InstallStatus
        New.CreateCommand=CreateCommand
        New.StakerWorkOrder=StakerWorkOrder
        New.StakerStationOverride=StakerStationOverride
        New.StakerRecipeNumber=StakerRecipeNumber
        New.TransformerBank=transformerBank
        New.Validate()
        New.save()
        return New
    def Validate(self):
        """Validate will raise an exception if the Assembly does not 'check out' """
        if(not self.Station and not self.Span):
            NoStationOrSpan=Exception()
            raise NoStationOrSpan
        #Add Other Tests Here 
    def GetPhaseCode(self, GetNeutral=False):
        """Returns the ABC Phase code for an assembly"""
        String=''
        if(self.PhaseAIndicator):
            String = String + 'A'
        if(self.PhaseBIndicator):
            String = String + 'B'
        if(self.PhaseCIndicator):
            String = String + 'C'
        if(GetNeutral and self.PhaseNeutralIndicator):
            String = String + 'N'
        return String
    def StringDetailed(self):
        StringList= []
        StringList.append('C-' + str(self.CircuitNumber))
        StringList.append(self.CompatibleUnit.StringDetailed())
        StringList.append(self.GetPhaseCode(GetNeutral=True))
        if(self.TagNumber):
            StringList.append(str(self.TagNumber))
        if(self.OpenIndicator):
            StringList.append(' Open ')
        if(self.IdleIndicator):
            StringList.append('Idle')
        if(self.PrimaryIndicator):
            StringList.append('Primary')
        if(self.SecondaryIndicator):
            StringList.append('Secondary')
        if(self.ServiceIndicator):
            StringList.append('Service')
        if(self.PoleLightIndicator):
            StringList.append(str("Light Pole"))
        if(self.PoleGuyIndicator):
            StringList.append(str("Guy Pole"))
        if(self.PoleStubIndicator):
            StringList.append(str("Stub Pole"))
        if(self.PoleMeterIndicator):
            StringList.append(str("Meter Pole"))
        if(self.MeterDescription):
            StringList.append("Meter Description:  " + self.MeterDescription)
        if(self.MeterLocationNumberFromCIS):
            StringList.append("Meter Location from CIS:  " + str(self.MeterLocationNumberFromCIS))
        if(self.MeterServiceType):
            StringList.append("Meter Service Type:  " + str(self.MeterServiceType))
        if(self.MeterDCSINumber):
            StringList.append("Meter DCSI Number:  " + str(self.MeterDCSINumber))
        if(self.MeterNumber):
            StringList.append("Meter Number:  " + str(self.MeterNumber))
        if(self.MeterForm):
            StringList.append("Meter Form:  " + str(self.MeterForm))
        if(self.MapNumber):
            StringList.append('MapNumber: ' + str(self.MapNumber))
        if(self.OldMapNumber):
            StringList.append('Old Map Number:  ' + str(self.OldMapNumber))
        if(self.SubstationName):
            StringList.append("Substation:  " + str(self.SubstationName))
        String = ' '.join(StringList)
        return String
    def GetProtectingAssemblyIndicator(self):
        if(self.CompatibleUnit.OpenPointIndicator or self.CompatibleUnit.CutOutIndicator or self.CompatibleUnit.RecloserIndicator or
           self.CompatibleUnit.RegulatorIndicator or self.CompatibleUnit.SwitchIndicator):
            if(not self.CompatibleUnit.Name == 'M5-9TR'):
                return True
        return False
    def GetSumOfPhaseCodes(self, Assemblies=[]):
        if(not Assemblies):
            Assemblies=[self]
        PhaseAIndicator=False
        PhaseBIndicator=False
        PhaseCIndicator=False
        PhaseNIndicator=False
        for assembly in Assemblies:
            if(assembly.PhaseAIndicator):
                PhaseAIndicator=True
            if(assembly.PhaseBIndicator):
                PhaseBIndicator=True
            if(assembly.PhaseCIndicator):
                PhaseCIndicator=True
            if(assembly.PhaseNeutralIndicator):
                PhaseNIndicator=True
        PhaseString=''
        if(PhaseAIndicator):
            PhaseString = PhaseString + 'A'
        if(PhaseBIndicator):
            PhaseString = PhaseString + 'B'
        if(PhaseCIndicator):
            PhaseString = PhaseString + 'C'
        if(PhaseNIndicator):
           PhaseString = PhaseString + 'N'
        return PhaseString
    def GetAssemblyOwnerName(self):
        if(self.AssemblyOwner):
            return self.AssemblyOwner.Name
        else:
            return ''
    def GetManufacturerName(self):
        if(self.Manufacturer):
            return self.Manufacturer.Name
        else:
            return ''
    def GetMeterFormName(self):
        if(self.MeterForm):
            return self.MeterForm.Name
        else:
            return ''
    def GetMeterServiceTypeName(self):
        if(self.MeterServiceType):
            return self.MeterServiceType.Name
        else:
            return ''
    def GetIndexWhenReverseSorted(self):
        Objects=Assembly.objects.all().order_by('-id')
        i = 0
        while(True):
            if(Objects[i] == self):
                return i
            i = i + 1
    def GetCommandidData(self):
        if(self.ResidesOnServerIndicator):
            return self.id, None
        return None, self.GetIndexWhenReverseSorted()
    def GetLongMapNumber(self):
        if(len(self.OldMapNumber) < 2):
            return 'UNKNOWN'
        Numbers=self.OldMapNumber.split('-')
        if(not Numbers[0]):
            return 'UNKNOWN, Initial "-"'
        if(Numbers[0][0] == 'E'):
            #Handle E Number here
            FirstNumber='500'
            SecondNumber=Numbers[0][1:].rjust(3, '0')
            if(len(Numbers) == 2):
                ThirdNumber=Numbers[1].rjust(5, '0')
            else:
                ThirdNumber=Numbers[1].rjust(2, '0') + Numbers[2].rjust(3, '0')                
            return FirstNumber + SecondNumber + ThirdNumber
        if(len(Numbers) == 4):
            FirstNumber=Numbers[0] + '00'
            SecondNumber=Numbers[1]
            ThirdNumber=Numbers[2].rjust(3, '0')
            FourthNumber=''
            FifthNumber=Numbers[3].rjust(3, '0')
            return FirstNumber + SecondNumber + ThirdNumber + FourthNumber + FifthNumber
        if(len(Numbers) == 5):
            FirstNumber=Numbers[0] + '00'
            SecondNumber=Numbers[1]
            ThirdNumber=Numbers[2]
            FourthNumber=Numbers[3].rjust(2, '0')
            FifthNumber=Numbers[4].rjust(3, '0')
            return FirstNumber + SecondNumber + ThirdNumber + FourthNumber + FifthNumber
        else:
            return 'Possibly Invalid GIS Map Number:  ' + self.OldMapNumber
    def GetNearestTagNumber(self):
        if(self.Span):
            return '' #This functionality is not implemented for span assemblies
        Assemblies=Assembly.objects.filter(Station=self.Station).exclude(TagNumber='').exclude(TagNumber__isnull=True).order_by('id')
        if(Assemblies):
            return Assemblies[0].TagNumber
        Stations=geography.Station.objects.filter(Point__distance_lte=(self.Station.Point, 
                                        50 * djangoproject.settings.COOPGISDistanceMultiplier)).exclude(id=self.Station.id).order_by('id')
        for i in Stations:
            Assemblies=Assembly.objects.filter(Station=i).exclude(TagNumber='').exclude(TagNumber__isnull=True).order_by('id')
            if(Assemblies):
                return Assemblies[0].TagNumber
        #2nd Chance to find a further away pole
        Stations=geography.Station.objects.filter(Point__distance_lte=(self.Station.Point, 
                                        300 * djangoproject.settings.COOPGISDistanceMultiplier)).exclude(id=self.Station.id).order_by('id')
        for i in Stations:
            Assemblies=Assembly.objects.filter(Station=i).exclude(TagNumber='').exclude(TagNumber__isnull=True).order_by('id')
            if(Assemblies):
                return Assemblies[0].TagNumber
        return ''
    def CalculateUpstreamAssemblies(self, CurrentStation=None, CircuitNumber=None, CurrentUpstreamAssembly = None):
        if(not CurrentStation):
            Substations=Assembly.objects.filter(CompatibleUnit__SubstationIndicator=True)
            for substation in Substations:
                Recloser=compatibleunit.Assembly.objects.filter(Station__Point__distance_lte=(substation.Station.Point, 1000 * djangoproject.settings.COOPGISDistanceMultiplier)).filter(CompatibleUnit__RecloserIndicator=True)



                Assembly.objects.filter(CircuitNumber=CircuitNumber).update(CurrentUpstreamAssembly=None) #Need to switch from substations to get the reclosers
                self.CalculateUpstreamAssemblies(substation, substation.CircuitNumber, CurrentUpstreamAssembly=substation)
            return 
        Assemblies=Assembly.objects.filter(StartStation=CurrentStation).filter(CircuitNumber=CircuitNumber).filter(ConductorIndicator=True).filter(CurrentUpstreamAssembly__isnull=True) | \
                   Assembly.objects.filter(EndStation=CurrentStation).filter(CircuitNumber=CircuitNumber).filter(ConductorIndicator=True).filter(CurrentUpstreamAssembly__isnull=True)
        for assembly in Assemblies:
            pass
            





class ProtectingAssembly(models.Model):
    """ProtectingAssembly is a list of assemblies that protect spans (CutOuts, Reclosers, etc.)"""
    Assembly=models.ForeignKey('Assembly', on_delete=models.CASCADE)
    Span=models.ForeignKey('Span', on_delete=models.CASCADE)
    objects=models.GeoManager()
    class Meta:
        db_table=u'coopgisprotectingassembly'
        app_label='djangoproject'
    def GetOrCreate(self, assembly, span):
        try:
            New=ProtectingAssembly.objects.get(Assembly=assembly, Span=span)
            return New
        except:
            pass
        New=ProtectingAssembly()
        New.Assembly=assembly
        New.Span=span
        New.save()
        return New

class CompatibleUnitPriceContract(models.Model):
    """Holds a list of contracts that compatibleunitprices can associate with"""
    Name=models.CharField(max_length=250, unique=True)
    Description=models.TextField(null=True, blank=True)
    ActiveIndicator=models.NullBooleanField(null=True, blank=True)
    StartDate=models.DateField()
    EndDate=models.DateField()
    CreateCommand=models.ForeignKey('Command', null=True, blank=True, on_delete=models.SET_NULL)
    Company=models.ForeignKey('Company', on_delete=models.PROTECT)
    ResidesOnServerIndicator=models.NullBooleanField()
    objects=models.GeoManager()
    class Meta:
        db_table=u'coopgiscompatibleunitpricecontract'
        app_label='djangoproject'
    def GetIndexWhenReverseSorted(self):
        Objects=CompatibleUnitPriceContract.objects.all().order_by('-id')
        i = 0
        while(True):
            if(Objects[i] == self):
                return i
            i = i + 1
    def GetCommandidData(self):
        if(self.ResidesOnServerIndicator):
            return self.id, None
        return None, self.GetIndexWhenReverseSorted()
    def __unicode__(self):
        return str(self.Name)

class LightRate(models.Model):
    """Holds a list of Types based on billing rates for various Lights"""
    # 7 at the end of a type indicates a pole charge
    Unit=models.TextField(db_column='unit')
    Type=models.TextField(db_column='type')
    Description=models.TextField(db_column='description')
    #Charge=models.FloatField #not within scope of module
    class Meta:
        db_table=u'coopgislightrate'
        app_label='djangoproject'


class CompatibleUnitPrice(models.Model):
    """Holds a List of Prices for Various Compatible Units"""
    Description=models.TextField(null=True, blank=True)
    CompatibleUnit=models.ForeignKey('CompatibleUnit', on_delete=models.PROTECT)
    CompatibleUnitPriceContract=models.ForeignKey('CompatibleUnitPriceContract', on_delete=models.PROTECT)
    CodedInstallPrice=models.FloatField()
    CodedRemovePrice=models.FloatField()
    ResidesOnServerIndicator=models.BooleanField()
    CreateCommand=models.ForeignKey('Command', null=True, blank=True, on_delete=models.SET_NULL)
    objects=models.GeoManager()
    class Meta:
        db_table=u'coopgiscompatibleunitprice'
        app_label='djangoproject'
    def __unicode__(self):
        return str(self.CompatibleUnit.Name) + str(round(self.CodedInstallPrice, 2))
    def GetDecodedInstallPrice(self, Adder, Multiplier):
        return (self.CodedInstallPrice/Multiplier)-Adder
    def GetDecodedRemovePrice(self, Adder, Multiplier):
        return (self.CodedRemovePrice/Multiplier)-Adder
    def GetIndexWhenReverseSorted(self):
        Objects=CompatibleUnitPrice.objects.all().order_by('-id')
        i = 0
        while(True):
            if(Objects[i] == self):
                return i
            i = i + 1
    def GetCommandidData(self):
        if(self.ResidesOnServerIndicator):
            return self.id, None
        return None, self.GetIndexWhenReverseSorted()
    def __unicode__(self):
        return str(self.CompatibleUnitPriceContract) + ' ' + str(self.CompatibleUnit) + ' ' + str(self.Description)


class CompatibleUnitStakerAdmin(admin.ModelAdmin):
    pass

#    list_display=['Name','Description', 'StakerPoleIndicator', 
#            'StakerTransformerIndicator', 'StakerMiscEquipmentIndicator', 'StakerGroundIndicator', 'StakerGuyGuyIndicator',
#            'StakerGuyAnchorIndicator', 'StakerSpanAssemblyIndicator', 'StakerUnitIndicator']
#    fields=['Name','Description', 'StakerPoleIndicator', 
#            'StakerTransformerIndicator', 'StakerMiscEquipmentIndicator', 'StakerGroundIndicator', 'StakerGuyGuyIndicator',
#            'StakerGuyAnchorIndicator', 'StakerSpanAssemblyIndicator', 'StakerUnitIndicator']
#    ordering=['Name']



try:
    admin.site.register(CompatibleUnit, CompatibleUnitStakerAdmin)
except:
    pass





class WarehouseMeterInventoryCheckIn(models.Model):
    MeterNumber=models.TextField()
    MeterDCSINumber=models.TextField()
    WarehouseMeterInspectionChoice=models.ForeignKey('WarehouseMeterInspectionChoice', null=True, blank=True, on_delete=models.PROTECT)
    Description=models.TextField(null=True, blank=True)
    Location=models.TextField(null=True, blank=True)
    JunkIndicator=models.NullBooleanField(null=True, blank=True)
    CheckInDateTime=models.DateTimeField(null=True, blank=True)
    CheckOutDateTime=models.DateTimeField(null=True, blank=True)
    InspectionDateTime=models.DateTimeField(null=True, blank=True)
    JunkDateTime=models.DateTimeField(null=True, blank=True)
    ResidesOnServerIndicator=models.BooleanField()
    class Meta:
        db_table=u'warehousemeterinventorycheckin'
        app_label='djangoproject'
    def GetIndexWhenReverseSorted(self):
        Objects=WarehouseMeterInventoryCheckIn.objects.all().order_by('-id')
        i = 0
        while(True):
            if(Objects[i] == self):
                return i
            i = i + 1
    def GetCommandidData(self):
        if(self.ResidesOnServerIndicator):
            return self.id, None
        return None, self.GetIndexWhenReverseSorted()
    def __unicode__(self):
        return str(self.MeterNumber.ljust(20) + str(self.MeterDCSINumber).ljust(20) + str(self.WarehouseMeterInspectionChoice).ljust(20) + 
                   str(self.Description).ljust(20) +
                   str(self.GetJunkIndicatorMark()).ljust(10) + str(self.GetShortDateTime(self.CheckInDateTime)).ljust(20) + 
                   str(self.GetShortDateTime(self.CheckOutDateTime)).ljust(20) + 
                   str(self.GetShortDateTime(self.InspectionDateTime)).ljust(20) +
                   str(self.GetShortDateTime(self.JunkDateTime)).ljust(20) + str(self.Location).ljust(20))
    def GetShortDateTime(self, DateTimeField):
        if(not DateTimeField):
            return ''
        return str(DateTimeField.month) + '/' + str(DateTimeField.day) + '/' + str(DateTimeField.year) + ' ' + str(DateTimeField.hour) + ':' + str(DateTimeField.minute)
    def GetHeadings(self):
        return ('MeterNumber'.ljust(20) + 'MeterDCSINumber'.ljust(20) + 'Inspection'.ljust(20) + 'Description'.ljust(20) + 'Junk'.ljust(10) + 
               'CheckInDateTime'.ljust(20) + 'CheckOutDateTime'.ljust(20) + 'InspectionDateTime'.ljust(20) + 'JunkDateTime'.ljust(20)  +
               'Location'.ljust(20))
    def GetJunkIndicatorMark(self):
        if(self.JunkIndicator):
            return 'X'
        else:
            return ''

    
class WarehouseMeterInspectionChoice(models.Model):
    Name=models.CharField(max_length=250, unique=True)
    Description=models.TextField(null=True, blank=True)
    ActiveIndicator=models.NullBooleanField(null=True, blank=True)
    ResidesOnServerIndicator=models.NullBooleanField()
    class Meta:
        db_table=u'warehousemeterinspectionchoice'
        app_label='djangoproject'
    def GetIndexWhenReverseSorted(self):
        Objects=WarehouseMeterInspectionChoice.objects.all().order_by('-id')
        i = 0
        while(True):
            if(Objects[i] == self):
                return i
            i = i + 1
    def GetCommandidData(self):
        if(self.ResidesOnServerIndicator):
            return self.id, None
        return None, self.GetIndexWhenReverseSorted()
    def __unicode__(self):
        return str(self.Name)


class GroundRodTest(models.Model):
    """GroundRodTest signifies ground rods that are driven at each pole which have their resistance tested"""
    Company=models.ForeignKey('Company', db_column='company', on_delete=models.PROTECT)
    CreateCommand=models.ForeignKey('Command', blank=True, null=True, on_delete=models.SET_NULL)   
    CreateDateTime=models.DateTimeField(db_column='createdatetime', null=True, blank=True)
    CreateUserName=models.TextField(db_column='createusername', null=True, blank=True)
    Description=models.TextField(db_column='description', null=True, blank=True)
    GroundRodNumber=models.IntegerField(db_column='groundrodnumber') #Must be populated, '0' = Original
    GroundRodTestDate=models.DateField(db_column='groundrodtestdate')
    InspectionPersonName=models.TextField(db_column='inspectionpersonname', null=True, blank=True)
    LastModifyDateTime=models.DateTimeField(db_column='lastmodifydatetime', null=True, blank=True)
    LastModifyUserName=models.TextField(db_column='lastmodifyusername', null=True, blank=True)
    Point=models.PointField(db_column='the_geom', srid=djangoproject.settings.COOPGISSRID)
    ResidesOnServerIndicator=models.NullBooleanField(db_column='residesonserverindicator', blank=True, null=True)
    ResistanceReading=models.FloatField(db_column='resistancereading', null=True, blank=True)
    SetupIndicator=models.NullBooleanField(db_column='setupindicator', null=True, blank=True)
    StationIdentifier=models.IntegerField(db_column='stationidentifier', blank=True, null=True)
    SubstationName=models.TextField(db_column='substationname', null=True, blank=True)
    WorkOrderNumber=models.TextField(db_column='workordernumber', null=True, blank=True) #Work Order Number For Company (not tracked in COOPGIS for now, 06/28/2010)   
    objects=models.GeoManager()
    def __unicode__(self):
        return str(self.CreateDateTime) + " " + str(self.GroundRodNumber)
    class Meta:
        db_table=u'coopgisgroundrodtest'
        app_label='djangoproject'

class TransformerBankType(models.Model):  #This table is not being used 
    Name=models.TextField(db_column='name', unique=True)
    Description=models.TextField(db_column='description', null=True, blank=True)
    def __unicode__(self):
        return str(self.Name)
    class Meta:
        db_table=u'transformerbanktype'
        app_label='djangoproject'
    def GetIndexWhenReverseSorted(self):
        Objects=TransformerBankType.objects.all().order_by('-id')
        i = 0
        while(True):
            if(Objects[i] == self):
                return i
            i = i + 1
    def GetCommandidData(self):
        if(self.ResidesOnServerIndicator):
            return self.id, None
        return None, self.GetIndexWhenReverseSorted()


class TransformerBank(models.Model):
    """TransformerBanks are collections of transformers connected together to supply various voltages """
    TransformerBankType=models.ForeignKey('transformerbanktype', db_column='banktype', null=True, blank=True)  
    Description=models.TextField(db_column='description', null=True, blank=True)
    Station=models.ForeignKey('Station', db_column='station')  #Calculated Field, based on the 1st transformer added to a transformer bank [or any transformer if no transformers are at the station]
    MaximumTransformerDistance=models.FloatField(db_column='maximumtransformerdistance', null=True, blank=True)  #Calculated field, max distance from station of any transformer that is part of this bank
    ResidesOnServerIndicator=models.NullBooleanField(db_column='residesonserverindicator', blank=True, null=True)
    objects=models.GeoManager()
    def __unicode__(self):
        return str(self.id) + '  ' + str(self.TransformerBankType.Name)
    class Meta:
        db_table=u'transformerbank'
        app_label='djangoproject'
    def GetIndexWhenReverseSorted(self):
        Objects=TransformerBank.objects.all().order_by('-id')
        i = 0
        while(True):
            if(Objects[i] == self):
                return i
            i = i + 1
    def GetCommandidData(self):
        if(self.ResidesOnServerIndicator):
            return self.id, None
        return None, self.GetIndexWhenReverseSorted()
    def CalculateStationAndMaximumTransformerDistance(self):
        pass





